Org-mode: Dynamic block
Un nouveau billet de blog pour te parler d'une fonctionnalité d'Org-mode très pratique: Les blocs de texte dynamique.
Comme son nom l'indique, il s'agit d'un bloc de texte, inséré dans un document Org-mode, dont le contenu sera généré dynamiquement par Emacs. Il existe plusieurs types de blocs, chacun générant un contenu différent. On peut paramétrer chaque bloc afin de personnaliser le contenu, chaque type de bloc acceptant des paramètres différents. Et il est aussi possible de créer de nouveaux types de blocs.
On va voir comment utiliser ces blocs mais aussi comment en créer un nouveau.
Avant de commencer
Avec les blocs dynamiques, il faut faire la différence entre:
- Le bloc qu'on ajoute dans un document Org-mode, qui sera d'un certain type
- Le contenu généré par le bloc
- La façon d'ajouter le bloc dans un document
Utilisation
Ajouter un bloc dans un document
Pour ajouter un bloc dynamique à un document Org-mode, on peut procéder de 2 façons:
- L'écrire sois-même
- Demander à Emacs d'écrire automatiquement le bloc
Pour la première option, on écrit simplement ceci:
#+BEGIN type-de-bloc #+END
Les balises #+BEGIN
et #+END
indiquent le début et la fin du bloc.
Il faut remplacer type-de-bloc
par le type de bloc qu'on souhaite.
On écrit rien entre les balises car c'est là que le contenu généré
dynamiquement sera écrit.
Pour demander à Emacs d'ajouter le bloc au lieu de l'écrire sois-même,
on peut appeler la fonction org-dynamic-block-insert-dblock
(raccourcis clavier C-c C-x x
). Emacs demandera le nom du type de
bloc qu'on souhaite utiliser et il insérera un exemple de ce bloc.
Demander au bloc de générer son contenu
Pour générer le contenue du bloc, il faut placer le curseur
d'écriture sur la ligne #+BEGIN
et appeler la fonction
org-dblock-update
(raccourcis clavier C-c C-c
).
Tout ce qui se trouve entre le #+BEGIN
et le #+END
sera effacé
et le texte généré y sera inséré.
Paramétrer le bloc
Il est possible de définir des paramètres pour le bloc, sur la même
ligne que la balise #+BEGIN
, sous cette forme:
#+BEGIN type-de-bloc :parametre_1 11 :parametre_2 42 #+END
Dans cette exemple, on a 2 paramètres: parametre_1
qui a pour valeur
11
et parametre_2
qui a pour valeur 42
.
Types de blocs proposés par Org-mode
Org-mode vient avec 2 types de blocs dynamiques: clocktable
et
columnview
. Le premier va insérer un tableau qui listera des tâches
qu'on a fait ainsi que le temps qu'on y a passé. Le second affichera
une arborescence d'un document Org-mode sous la forme d'un tableau.
Comme cette article est déjà assez long, je ne vais pas détailler
l'utilisation de ces 2 blocs ici. Mais je t'invite à aller lire la
documentation de clocktable
et celle de columnview
.
Créer un nouveau type de bloc
Pour ce nouveau type de bloc, je vais prendre un exemple simple: Un bloc qui va répéter une phrase.
Il sera nommé example
, va accepter le paramètre :text
et le contenu
généré sera une copie du texte reçu comme paramètre.
Définition du nouveau type de bloc
Je commence par écrire une fonction Emacs-lisp
comme celle-ci:
(defun org-dblock-write:example (params) (let ((text (plist-get params :text))) (insert text)))
Le nom de cette fonction à pour préfixe org-dblock-write:
et accepte
un seul paramètre d'entrée: params
. Le nom du type de bloc est écrit dans le
nom de la fonction, après le préfixe. Le paramètre est une plist
dans laquelle on retrouve tous les paramètres du bloc. On peut accéder
à ces paramètres avec la fonction (plist-get)
.
Le code de cette fonction est simple: On stock le contenu du paramètre
:text
dans la variable locale text
. Puis on passe le contenu de
cette variable à la fonction (insert)
. Le texte sera automatiquement
inséré à l'intérieur de notre bloc dynamique au moment où son contenu
sera généré.
On peut maintenant demander à Emacs d'évaluer cette nouvelle fonction.
Elle pourrait être plus simple pour ce qu'on en fait ici. Mais cette exemple, où on utilise une variable locale, est également un bon point de départ si tu souhaite faire un type de bloc plus complexe.
Utilisation du nouveau type de bloc
Maintenant, on peut utiliser le nouveau type de bloc dans un document
Org-mode. Mais on doit écrire sois-même les balises #+BEGIN
et
#+END
ainsi que le nom du bloc comme ceci:
#+BEGIN: example :text "Ceci est un test" #+END
Ici, on précise que le type de bloc est example
et on lui donne le
paramètre :text
avec pour valeur "Ceci est un test".
Maintenant, si on génère le contenu du bloc avec org-dblock-update
(raccourcis C-c C-c
), voici ce qu'on obtient:
#+BEGIN: example :text "Ceci est un test" Ceci est un test #+END
Ça fonctionne. Simple et efficace.
Écriture automatique d'un bloc dans un document Org-mode
On a un nouveau type de bloc, mais si on veut l'utiliser on doit écrire les balises sois-même. La prochaine étape est d'automatiser l'écriture du bloc, par Emacs.
Et pour ça, on va simplement écrire et évaluer une fonction
Emacs-lisp
interactive. Cette fonction va insérer un exemple de
bloc, utilisant notre nouveau type, là où se trouve le curseur
d'écriture.
Voici le code de cette fonction:
(defun org-example-insert-dblock () "Create a dynamic block that show an example text" (interactive) (org-create-dblock (list :name "example" :text "Un autre example à insérer")))
Elle va appeler une autre fonction: (org-create-dblock)
. Cette autre
fonction accepte comme paramètre une plist
, indiquant toutes les
propriétés utilisées pour créer le bloc. Ici on précise 2 paramètres:
:name
est le nom du type de bloc et :text
est le paramètre :text
du bloc. On indique la valeur de :text
comme étant la chaine de
caractère "Un autre example à insérer"
.
Comme cette nouvelle fonction est interactive, on peut l'appeler avec
le raccourcis M-x
. Si on essaye dans un document Org-mode, voici le
résultat qui sera inséré:
#+BEGIN: example :text "Un autre example à insérer" #+END:
Notre bloc de type example
, avec un paramètre :text
déjà définit.
À noter que dans notre exemple, la fonction
(org-example-insert-dblock)
définit la valeur de :text
de façon
statique. Mais on peut aussi définir n'importe quel paramètre du bloc
de façon dynamique.
Maintenant qu'on a une fonction pouvant insérer un bloc de type
example
, il faut dire à Emacs qu'il peut la proposer quand on
appelle org-dynamic-block-insert-dblock
.
Pour ça, il suffit d'écrire et d'évaluer le code Emacs-lisp
suivant:
(org-dynamic-block-define "example" 'org-example-insert-dblock)
L'appelle à la fonction (org-dynamic-block-define)
va associer le
nom example
avec la fonction org-example-insert-block
.
Maintenant si, dans un document Org-mode, on appelle
org-dynamic-block-insert-dblock
(raccourcis C-c C-x x
) et qu'on
lui indique le type de bloc example
, voici ce qui sera inséré:
#+BEGIN: example :text "Un autre example à insérer" #+END:
Conclusion
Org-mode propose un excellent moyen de générer dynamiquement des blocs de texte.
L'exemple vu dans ce billet est plutôt simple: On a va seulement insérer un texte, pré-définit par un paramètre. Mais on peut faire bien plus.
Par exemple:
- Un bloc de type
index
, qui listerai tous les documents Org-mode d'un dossier - Un bloc
available-books
, qui listerai tout les livres d'une liste de lecture qui seraient disponibles à la bibliothèque ou chez son libraire préféré - Un bloc de type
machine-list
, qui listerai tout les ordinateurs détectés sur le réseau parnmap
, ou qui générerai un tableau avec toutes les informations récupérées - Un bloc de type
next-trains
, qui listerai les départs d'un train pour une date, très utile pour préparer ses vacances
Les blocs dynamiques proposent un large éventail de possibilités. Et pour créer de nouveau types, vous avez accès à toutes les bibliothèques disponibles pour Emacs.
Pour en apprendre plus, n'hésite pas à lire la documentation des
blocs dynamiques ainsi que celle des fonctions Emacs-lisp
utilisée
dans de billet de blog.